#pragma once
#include <iostream>
#include <vector>
#include <cassert>

#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
using namespace std;


template<class T>
class RingQueue
{
    static const int max_cap = 10;
public:
    RingQueue(int cap = max_cap) :_v(cap),_cap(cap)
    {
        sem_init(&_SpaceSem,0,_cap);
        sem_init(&_DataSem,0,0);
        pthread_mutex_init(&_Pmtx,nullptr);
        pthread_mutex_init(&_Cmtx,nullptr);

        _ProductorStep = _ComsumerStep = 0;
    }

    void P(sem_t& Sem)
    {
        int n = sem_wait(&Sem); //申请成功信号量-1
        assert(n == 0);
    }

    void V(sem_t& Sem)
    {
        int n = sem_post(&Sem); //归还成功，信号量+1
        assert(n == 0);
    }

    void push(T& data)
    {
        P(_SpaceSem); //申请信号量
        pthread_mutex_lock(&_Pmtx);
        //进行生产
        _v[_ProductorStep++] = data;
        _ProductorStep %= _cap;
        pthread_mutex_unlock(&_Pmtx);
        V(_DataSem); //数据资源+1
    }

    void pop(T* data)
    {
        P(_DataSem);
        pthread_mutex_lock(&_Cmtx);
        //进行消费
        *data = _v[_ComsumerStep++];
        _ComsumerStep %= _cap;
        pthread_mutex_unlock(&_Cmtx);
        V(_SpaceSem);
    }

    ~RingQueue()
    {
        sem_destroy(&_SpaceSem);
        sem_destroy(&_DataSem);
        pthread_mutex_destroy(&_Pmtx);
        pthread_mutex_destroy(&_Cmtx);
    }

private:
    vector<T> _v; //数组模拟环形队列
    int _cap; //环形队列容量
    sem_t _SpaceSem; //生产要生产，看中的是空间资源
    sem_t _DataSem; //消费者要消费，看中的是数据资源
    int _ProductorStep; //生产者位置
    int _ComsumerStep; //消费者位置
    pthread_mutex_t _Pmtx; //生产者与生产者之间互斥
    pthread_mutex_t _Cmtx; //消费者与消费者之间互斥
};
